import { useCallback, useEffect, useRef, useReducer} from "react";
import {reducerMediaResultReducer} from './reducer';


function adaptorGetUserMedia(constraints: MediaStreamConstraints): Promise<MediaStream> {
    if(navigator.mediaDevices.getUserMedia) {
        // 会提示用户给予使用媒体输入的许可
        return navigator.mediaDevices.getUserMedia(constraints);
    }
    const getUserMedia = (navigator as any).webkitGetUserMedia ?? (navigator as any).mozGetUserMedia;
    // 为老的 navigator.getUserMedia 方法包裹一个 Promise
    if(getUserMedia) {
        return new Promise((resolve, reject) => {
            getUserMedia.call(navigator, constraints,resolve, reject)
        })
    }
    const error = new Error('getUserMedia is not implemented in this browser');
    (error as any).code = 'ERR_METHOD_NOT_INPLEMENT'
    return Promise.reject(error);
}

interface UserMediaHook {
    stream: MediaStream | null;
    recording: boolean;
    error: Error | null;
    start: () => void;
    stop: () => void
}

const DEFAULT_CONSTRAINTS = {
    video: true,
    audio: true,
}

export default function useUserMedia(
    constraints: MediaStreamConstraints,
    onSuccess: (stream: MediaStream) => void,
    onError: (error: Error)=> void
):UserMediaHook {
    const [{recording, error}, dispatch] = useReducer(reducerMediaResultReducer, {recording: false, error: null})
    const streamRef = useRef<MediaStream | null>(null);
    const stop = useCallback(() => {
        if(streamRef.current) {
            // 拿到所有的媒体流
            const tracks: MediaStreamTrack[]= streamRef.current.getTracks();
            tracks.forEach((track:MediaStreamTrack) => {
                track.stop()
                dispatch({type: 'stop'})
            })
            streamRef.current = null;
        }
    },[])
    const start = useCallback(async () => {
        try {
            stop();
            const constraintsParams = constraints ?? DEFAULT_CONSTRAINTS;
            const stream = await adaptorGetUserMedia(constraintsParams); // 拿到媒体流
            streamRef.current = stream;
            dispatch({type: 'success'})
            onSuccess && onSuccess(stream);
        } catch (error: any) {
            dispatch({type: 'error', payload: error})
            onError && onError(error)
        }
    }, [])
    // 进入组件时，强制把所有stream track全部关闭
    useEffect(() => {stop()}, [stop])
    return {
        recording,
        error,
        stop,
        start,
        stream: streamRef.current
    }
}